{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "github地址:[https://github.com/cheesezh/python_design_patterns](https://github.com/cheesezh/python_design_patterns)\n",
    "\n",
    "## 单例模式\n",
    "\n",
    "单例模式（Singleton Pattern）是一种常用的软件设计模式，该模式的主要目的是`确保某一个类只有一个实例存在`。当你希望在整个系统中，某个类只能出现一个实例时，单例模式就能派上用场。\n",
    "\n",
    "比如，某个服务器程序的配置信息存放在一个文件中，客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间，有很多地方都需要使用配置文件的内容，也就是说，很多地方都需要创建 AppConfig 对象的实例，这就导致系统中存在多个 AppConfig 的实例对象，而这样会严重浪费内存资源，尤其是在配置文件内容很多的情况下。事实上，类似 AppConfig 这样的类，我们希望在程序运行期间只存在一个实例对象。\n",
    "\n",
    "在 Python 中，我们可以用多种方法来实现单例模式。\n",
    "\n",
    "### 使用模块\n",
    "\n",
    "其实，Python 的模块就是天然的单例模式，因为模块在第一次导入时，会生成 .pyc 文件，当第二次导入时，就会直接加载 .pyc 文件，而不会再次执行模块代码。因此，我们只需把相关的函数和数据定义在一个模块中，就可以获得一个单例对象了。如果我们真的想要一个单例类，可以考虑这样做："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "# mysingleton.py\n",
    "class Singleton(object):\n",
    "    def foo(self):\n",
    "        pass\n",
    "singleton = Singleton()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将上面的代码保存在文件 mysingleton.py 中，要使用时，直接在其他文件中导入此文件中的对象，这个对象即是单例模式的对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "from a import singleton"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.A object at 0x103496668>\n",
      "<__main__.A object at 0x103496668>\n"
     ]
    }
   ],
   "source": [
    "def Singleton(cls):\n",
    "    _instance = {}\n",
    "\n",
    "    def _singleton(*args, **kargs):\n",
    "        if cls not in _instance:\n",
    "            _instance[cls] = cls(*args, **kargs)\n",
    "        return _instance[cls]\n",
    "\n",
    "    return _singleton\n",
    "\n",
    "\n",
    "@Singleton\n",
    "class A(object):\n",
    "    a = 1\n",
    "\n",
    "    def __init__(self, x=0):\n",
    "        self.x = x\n",
    "\n",
    "\n",
    "a1 = A(2)\n",
    "a2 = A(3)\n",
    "print(a1)\n",
    "print(a2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一般情况，大家以为这样就完成了单例模式，但是这样`当使用多线程时会存在问题`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n",
      "<__main__.Singleton object at 0x1033e84a8>\n"
     ]
    }
   ],
   "source": [
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        pass\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "import threading\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print(obj)\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看起来也没有问题，那是因为执行速度过快，如果在init方法中有一些IO操作，就会发现问题了，下面我们通过time.sleep模拟"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Singleton object at 0x1033b79e8>\n",
      "<__main__.Singleton object at 0x1033b7e10>\n",
      "<__main__.Singleton object at 0x103401ef0>\n",
      "<__main__.Singleton object at 0x103401c18>\n",
      "<__main__.Singleton object at 0x103401048>\n",
      "<__main__.Singleton object at 0x103401dd8>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401eb8>\n",
      "<__main__.Singleton object at 0x103401a58>\n",
      "<__main__.Singleton object at 0x103401fd0>\n"
     ]
    }
   ],
   "source": [
    "class Singleton(object):\n",
    "\n",
    "    def __init__(self):\n",
    "        import time\n",
    "        time.sleep(0.5)\n",
    "        pass\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "import threading\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print(obj)\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "问题出现了！按照以上方式创建的单例，无法支持多线程。\n",
    "\n",
    "解决办法：加锁！未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n",
      "<__main__.Singleton object at 0x103401b00>\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        time.sleep(0.5)\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        with Singleton._instance_lock:\n",
    "            if not hasattr(Singleton, \"_instance\"):\n",
    "                Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print(obj)\n",
    "    \n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()\n",
    "time.sleep(5)\n",
    "obj = Singleton.instance()\n",
    "print(obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样就差不多了，但是还是有一点小问题，就是当程序执行时，执行了time.sleep(5)后，下面实例化对象时，此时已经是单例模式了，但我们还是加了锁，这样不太好，再进行一些优化，需要修改一下intance方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n",
      "<__main__.Singleton object at 0x1033db550>\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        time.sleep(0.5)\n",
    "\n",
    "    @classmethod\n",
    "    def instance(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            with Singleton._instance_lock:\n",
    "                if not hasattr(Singleton, \"_instance\"):\n",
    "                    Singleton._instance = Singleton(*args, **kwargs)\n",
    "        return Singleton._instance\n",
    "\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton.instance()\n",
    "    print(obj)\n",
    "    \n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()\n",
    "    \n",
    "time.sleep(5)\n",
    "obj = Singleton.instance()\n",
    "print(obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这种方式实现的单例模式，使用时会有限制，以后实例化必须通过`obj = Singleton.instance()`，如果用`obj=Singleton()`,这种方式得到的不是单例。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用__new__方法（推荐使用，方便）\n",
    "\n",
    "通过上面例子，我们可以知道，当我们实现单例时，为了保证线程安全需要在内部加入锁。\n",
    "\n",
    "我们知道，当我们实例化一个对象时，是先执行了类的__new__方法（我们没写时，默认调用object.__new__）实例化对象；然后再执行类的__init__方法，对这个对象进行初始化，所有我们可以基于这个机制，实现单例模式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Singleton object at 0x103483b70> <__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n",
      "<__main__.Singleton object at 0x103483b70>\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "import time\n",
    "class Singleton(object):\n",
    "    _instance_lock = threading.Lock()\n",
    "\n",
    "    def __init__(self):\n",
    "        time.sleep(0.5)\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        if not hasattr(Singleton, \"_instance\"):\n",
    "            with Singleton._instance_lock:\n",
    "                if not hasattr(Singleton, \"_instance\"):\n",
    "                    Singleton._instance = object.__new__(cls)  \n",
    "        return Singleton._instance\n",
    "\n",
    "obj1 = Singleton()\n",
    "obj2 = Singleton()\n",
    "print(obj1,obj2)\n",
    "\n",
    "def task(arg):\n",
    "    obj = Singleton()\n",
    "    print(obj)\n",
    "\n",
    "for i in range(10):\n",
    "    t = threading.Thread(target=task,args=[i,])\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "采用这种方式的单例模式，以后实例化对象时，和平时实例化对象的方法一样`obj = Singleton()`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用metaclass\n",
    "\n",
    "1. 类由type创建，创建类时，type的__init__方法自动执行，类()执行type的__call__方法(类的__new__方法,类的__init__方法)\n",
    "2. 对象由类创建，创建对象时，类的__init__方法自动执行，对象()执行类的__call__方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Foo __init__\n",
      "Foo __call__\n"
     ]
    }
   ],
   "source": [
    "class Foo:\n",
    "    def __init__(self):\n",
    "        print(\"Foo __init__\")\n",
    "\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        print(\"Foo __call__\")\n",
    "\n",
    "# 执行type的 __call__ 方法\n",
    "# 调用 Foo类（是type的对象）的 __new__方法，用于创建对象\n",
    "# 然后调用 Foo类（是type的对象）的 __init__方法，用于对对象初始化。\n",
    "obj = Foo()\n",
    "\n",
    "# 执行Foo的 __call__ 方法\n",
    "obj()    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cls <class '__main__.Foo'>\n"
     ]
    }
   ],
   "source": [
    "class SingletonType(type):\n",
    "    def __init__(self,*args,**kwargs):\n",
    "        super(SingletonType,self).__init__(*args,**kwargs)\n",
    "\n",
    "    def __call__(cls, *args, **kwargs): # 这里的cls，即Foo类\n",
    "        print('cls',cls)\n",
    "        obj = cls.__new__(cls,*args, **kwargs)\n",
    "        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)\n",
    "        return obj\n",
    "\n",
    "class Foo(metaclass=SingletonType): # 指定创建Foo的type为SingletonType\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        return object.__new__(cls)\n",
    "\n",
    "obj = Foo('xx')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Foo object at 0x10348d908>\n",
      "<__main__.Foo object at 0x10348d908>\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "\n",
    "class SingletonType(type):\n",
    "    _instance_lock = threading.Lock()\n",
    "    def __call__(cls, *args, **kwargs):\n",
    "        if not hasattr(cls, \"_instance\"):\n",
    "            with SingletonType._instance_lock:\n",
    "                if not hasattr(cls, \"_instance\"):\n",
    "                    cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)\n",
    "        return cls._instance\n",
    "\n",
    "class Foo(metaclass=SingletonType):\n",
    "    def __init__(self,name):\n",
    "        self.name = name\n",
    "\n",
    "\n",
    "obj1 = Foo('name')\n",
    "obj2 = Foo('name')\n",
    "print(obj1)\n",
    "print(obj2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考文章: [Python中的单例模式的几种实现方式的及优化](https://www.cnblogs.com/huchong/p/8244279.html)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
